#ifndef BACKEND_H
#define BACKEND_H
#include <QMap>
#include <QImage>
#include <QQmlContext>
#include<QDebug>
#include <QByteArray>
#include<QBuffer>
#include<QString>
#include <opencv2/opencv.hpp>
#include <QString>
#include<QWindow>
#include<QDateTime>
#include "line2Dup.h"
#include<opencv2/dnn.hpp>
#include"matchResult.h"
class Backend : public QObject {
    Q_OBJECT
    Q_PROPERTY(float angleStart READ getAngleStart WRITE setAngleStart NOTIFY angleStartChanged)
    Q_PROPERTY(float angleExtent READ getAngleExtent WRITE setAngleExtent NOTIFY angleExtentChanged)
    Q_PROPERTY(float angleStep READ getAngleStep WRITE setAngleStep NOTIFY angleStepChanged)
    Q_PROPERTY(float scaleMin READ getScaleMin WRITE setScaleMin NOTIFY scaleMinChanged)
    Q_PROPERTY(float scaleMax READ getScaleMax WRITE setScaleMax NOTIFY scaleMaxChanged)
    Q_PROPERTY(float scaleStep READ getScaleStep WRITE setScaleStep NOTIFY scaleStepChanged)
    Q_PROPERTY(float weak_thresh READ getWeakThresh WRITE setWeakThresh NOTIFY weakThreshChanged)
    Q_PROPERTY(float strong_thresh READ getStrongThresh WRITE setStrongThresh NOTIFY strongThreshChanged)
    Q_PROPERTY(bool sub_pixel READ getSub_pixel WRITE setSub_pixel NOTIFY sub_pixelChanged)
    Q_PROPERTY(float minScore READ getMinScore WRITE setMinScore NOTIFY minScoreChanged)
    Q_PROPERTY(float maxOverlap READ getMaxOverlap WRITE setMaxOverlap NOTIFY maxOverlapChanged)
    Q_PROPERTY(int numMatches READ getNumMatches WRITE setNumMatches NOTIFY numMatchesChanged)
    Q_PROPERTY(int threshold1 READ getThreshold1 WRITE setThreshold1 NOTIFY threshold1Changed)
    Q_PROPERTY(int threshold2 READ getThreshold2 WRITE setThreshold2 NOTIFY threshold2Changed)
public:
    explicit Backend(QObject *parent = nullptr) : QObject(parent) {}
    inline int getAngleStart()const{
        return static_cast<int>(std::round(angleStart*100));
    }
    inline int getAngleExtent()const{
        return static_cast<int>(std::round(angleExtent*100));
    }
    inline int getAngleStep()const{
        return static_cast<int>(std::round(angleStep*100));
    }
    inline int getScaleMin()const{
        return static_cast<int>(std::round(scaleMin*100));
    }
    inline int getScaleMax()const{
        return static_cast<int>(std::round(scaleMax*100));
    }
    inline int getScaleStep()const{
        return static_cast<int>(std::round(scaleStep*100));
    }
    inline int getWeakThresh()const{
        return static_cast<int>(std::round(weak_thresh));
    }
    inline int getStrongThresh()const{
        return static_cast<int>(std::round(strong_thresh));
    }
    inline bool getSub_pixel()const {
        return sub_pixel;
    }
    inline int getMinScore()const{
         return static_cast<int>(std::round(minScore*100));
    }
    inline int getMaxOverlap()const{
        return static_cast<int>(std::round(maxOverlap*100));
    }
    inline int getNumMatches()const{
        return numMatches;
    }
    inline int getThreshold1() {
        return threshold1;
    }
    inline int getThreshold2() {
       return threshold2;
    }
    inline void setAngleStart(int newValue){
        float temp = static_cast<float>(newValue)/100;
        if (angleStart != temp) {
            angleStart = temp;
            std::cout << "angleStart:" << angleStart << std::endl;
            emit angleStartChanged();
        }
    }
    inline void setAngleExtent(int newValue){
        float temp = static_cast<float>(newValue) / 100;
        if (angleExtent != temp) {
            angleExtent = temp;
            std::cout << "angleExtent:" << angleExtent << std::endl;
            emit angleExtentChanged();
        }
    }
    inline void setAngleStep(int newValue){
        float temp = static_cast<float>(newValue) / 100;
        if (angleStep != temp) {
            angleStep = temp;
            std::cout << "angleStep:" << angleStep << std::endl;
            emit angleStepChanged();
        }
    }
    inline void setScaleMin(int newValue){
        float temp = static_cast<float>(newValue) / 100;
        if (scaleMin !=temp) {
            scaleMin = temp;
            std::cout << "scaleMin:" << scaleMin << std::endl;
            emit scaleMinChanged();
        }
    }
    inline void setScaleMax(int newValue){
        float temp= static_cast<float>(newValue) / 100;
        if (scaleMax != temp) {
            scaleMax = temp;
            std::cout << "scaleMax:" << scaleMax << std::endl;
            emit scaleMaxChanged();
        }
    }
    inline void setScaleStep(int newValue){
        float temp = static_cast<float>(newValue) / 100;
        if (scaleStep!=temp) {
            scaleStep = temp;
            std::cout << "scaleStep:" << scaleStep << std::endl;
            emit scaleStepChanged();
        }
    }
    //和前端保持一致
    inline void setWeakThresh(int newValue){
        float temp = static_cast<float>(newValue);
        if (weak_thresh != temp) {
            weak_thresh = temp;
            std::cout << "weak_thresh:" << weak_thresh << std::endl;
            emit weakThreshChanged();
        }
    }
    inline void setStrongThresh(int newValue){
        float temp = static_cast<float>(newValue);
        if (strong_thresh != temp) {
            strong_thresh = temp;
            std::cout << "strong_thresh:" << strong_thresh << std::endl;
            emit strongThreshChanged();
        }
    }
    inline void setSub_pixel(bool newValue) {
        if (sub_pixel != newValue) {
            sub_pixel = newValue;
        }
    }
    inline void setMinScore(int newValue){
        float temp = static_cast<float>(newValue)/100;
        if (minScore != temp) {
            minScore = temp;
            std::cout << "minScore:" << minScore << std::endl;
            emit minScoreChanged();
        }
    }
    inline void setMaxOverlap(int newValue){
        float temp = static_cast<float>(newValue) / 100;
        if (maxOverlap != temp) {
            maxOverlap = temp;
            std::cout << "maxOverlap:" << maxOverlap << std::endl;
            emit maxOverlapChanged();
        }
    }
    inline void setNumMatches(int newValue){
        if (numMatches != newValue) {
            numMatches = newValue;
            std::cout << "numMatches:" << numMatches << std::endl;
            emit numMatchesChanged();
        }
    }
    inline void setThreshold1(int newValue) {
        if (threshold1 != newValue) {
            threshold1 = newValue;
            std::cout << "threshold1:" << threshold1 << std::endl;
            emit threshold1Changed();
        }
    }
    inline void setThreshold2(int newValue) {
        if (threshold2 != newValue) {
            threshold2 = newValue;
            std::cout << "threshold2:" << threshold2 << std::endl;
            emit threshold2Changed();
        }
    }
    //mat转qimage
    QImage cvMat2QImage(const cv::Mat &mat);
    //读模板
    Q_INVOKABLE void loadTemplateImage(const QString &path);
    //读目标图
    Q_INVOKABLE void loadTargetImage(const QString &path);

    Q_INVOKABLE void loadTargetFolder(const QString& path);
    //创建模板
    Q_INVOKABLE void createTemplate();
    //寻找模板
    Q_INVOKABLE void findTemplate();
    //提取边缘
    Q_INVOKABLE void getTemplateEdges();

    //橡皮擦
    Q_INVOKABLE void erase(double x,double y,double width,double height);

    //上一张
    Q_INVOKABLE void previous_target_image();

    //下一张
    Q_INVOKABLE void next_target_image();

    //保存模板
    Q_INVOKABLE void saveTemplateImage(const QString& path);

    //裁剪
    Q_INVOKABLE void cropTargetImage(double x,double y, double width, double height,double angle);
signals:
    void templateProcessed(const QString &imagePath);
    void imageProcessed(const QString &imagePath);
    void angleStartChanged();
    void angleExtentChanged();
    void angleStepChanged();
    void scaleMinChanged();
    void scaleMaxChanged();
    void scaleStepChanged();
    void weakThreshChanged();
    void strongThreshChanged();
    void sub_pixelChanged();
    void minScoreChanged();
    void maxOverlapChanged();
    void numMatchesChanged();
    void templateImgChanged();
    void threshold1Changed();
    void threshold2Changed();
private:
    std::string class_id="";
    line2Dup::Detector detector;
    shape_based_matching::shapeInfo_producer shapes;
    QMap<QString,QImage> targetImageCache;
    QMap<QString,QImage> templateImageCache;
    friend class ImageProvider;  // 允许ImageProvider访问imageCache
    float angleStart=0.0f;
    float angleExtent=359.99f;
    float angleStep=0.0f;
    float scaleMin=0.9f;
    float scaleMax=1.1f;
    float scaleStep=0.0f;
    float weak_thresh = 45.0f;
    float strong_thresh = 15.0f;
    bool sub_pixel = true;
    float minScore=0.7f;
    float maxOverlap=0.1f;
    int numMatches=0;
    int threshold1=100;
    int threshold2=200;
    cv::Mat templateImg;
    cv::Mat templateEdges;
    cv::Mat templateModel;
    QImage templateQImg;
    cv::Mat targetImg;
    std::vector<QString>imagePaths;
    int imagePathsIndex = 0;
    //create
    void createScaledShapeModel(cv::Mat& templateImg, line2Dup::Detector& detector, shape_based_matching::shapeInfo_producer& shapes, const std::string& class_id, float angleStart, float angleExtent, float angleStep, float scaleMin, float scaleMax, float scaleStep, float weak_thresh = 30.0f, float strong_thresh = 60.0f, bool set_produce_dxy = false);
    //find
    cv::Mat findScaledShapeModel(cv::Mat& templateImg, cv::Mat& targetImg, const std::string& class_id, line2Dup::Detector& detector, shape_based_matching::shapeInfo_producer& shapes, float minScore, int numMatches, float maxOverlap);

    
    std::vector<MatchResult>findScaledShapeModel1(cv::Mat& templateImg, cv::Mat& targetImg, const std::string& class_id, line2Dup::Detector& detector, shape_based_matching::shapeInfo_producer& shapes, float minScore, int numMatches, float maxOverlap);
};
#endif // BACKEND_H
